//! 执行 cargo r 运行 mainprocess。
//! mainprocess 调用自身（cargo r subprocess）执行 subprocess 并且捕获子进程的标准输入输出。
//! 然后在 mainprocess 中我们通过子进程的标准输入输出和 subprocess 进行通信。

use std::io::{BufRead, BufReader, Write};
use std::process::{Command, Stdio};

fn main() {
    match std::env::args().skip(1).next().as_deref() {
        None => mainprocess(),
        Some("subprocess") => subprocess(),
        _ => panic!("invalid command"),
    }
}

/// 子进程
pub fn subprocess() {
    for line in BufReader::new(std::io::stdin())
        .lines()
        .filter_map(Result::ok)
    {
        println!("{line}");
    }
}

/// 主进程
pub fn mainprocess() {
    let mut subprocess = Command::new("cargo")
        .arg("r")
        .arg("subprocess")
        // 在子进程和父进程之间建立输入管道
        .stdin(Stdio::piped())
        // 在子进程和父进程之间建立输出管道
        .stdout(Stdio::piped())
        // 执行子进程
        .spawn()
        .expect("failed to execute process");

    // 获得子进程的输入输出流
    let Some(mut stdin) = subprocess.stdin.take() else {
        panic!("unable to obtain standard input and output for child processes");
    };
    let Some(stdout) = subprocess.stdout.take().map(BufReader::new) else {
        panic!("unable to obtain standard input and output for child processes");
    };

    // 从子进程输出流读取数据
    std::thread::spawn(|| {
        for line in stdout.lines().filter_map(Result::ok) {
            println!("subprocess echo: {line}");
        }
    });

    // 向子进程输入流写入数据
    for line in BufReader::new(std::io::stdin())
        .lines()
        .filter_map(Result::ok)
    {
        stdin.write_all(format!("{line}\n").as_bytes()).unwrap();
    }
}
